#ifndef JEGEO_MODEL_H
#define JEGEO_MODEL_H
#include <vector>
#include <iostream>

namespace jegeo {

#ifdef JEGEO_REAL_TYPE
using jereal = JEGEO_REAL_TYPE;
#else
using jereal = double;
#endif

constexpr int CAP_STYLE_FLAT = 0x00;
constexpr int CAP_STYLE_SQUARE = 0x10;
constexpr int CAP_STYLE_ROUND = 0x20;

template<typename T>
using Point = std::tuple<T, T>;

template<typename T>
using Circle = std::tuple<T, T, T>;

template<typename T>
using Line = std::tuple<T, T, T, T>;

template<typename T>
using Segment = std::tuple<T, T, T, T>;

template<typename T>
using Size = std::tuple<T, T>;

template<typename T>
using Margins = std::tuple<T, T, T, T>;

template<typename T> //xs,ys,se,ye,xc,yc,cw
using Arc = std::tuple<T, T, T, T, T, T, bool>;

template<typename T>
using Rect = std::tuple<T, T, T, T>;

template<typename T>
using Vertex = std::tuple<T, T, jereal>;

template<typename T>
using Edge = std::tuple<T, T, T, T, jereal>;

template<typename T>
using VertexList = std::vector<Vertex<T>>;

template<typename T> // vertices, ishole
using Polyline = std::tuple<VertexList<T>, bool>;

template<typename T>
using Polygon = std::vector<Polyline<T>>;

template<typename T>
using PolylineList = std::vector<Polyline<T>>;

template<typename T>
using EdgeList = std::vector<Edge<T>>;

template<typename T>
using PointList = std::vector<Point<T>>;



// point
template<typename T>
inline T px(const Point<T> &p) { return std::get<0>(p);}
template<typename T>
inline T py(const Point<T> &p) { return std::get<1>(p);}
template<typename T>
inline void set_px(Point<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_py(Point<T> &p, T v) { std::get<1>(p)=v;}

// line, segment, rect
template<typename T>
inline T psx(const Line<T> &p) { return std::get<0>(p);}
template<typename T>
inline T psy(const Line<T> &p) { return std::get<1>(p);}
template<typename T>
inline T pex(const Line<T> &p) { return std::get<2>(p);}
template<typename T>
inline T pey(const Line<T> &p) { return std::get<3>(p);}
template<typename T>
inline void set_psx(Line<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_psy(Line<T> &p, T v) { std::get<1>(p)=v;}
template<typename T>
inline void set_pex(Line<T> &p, T v) { std::get<2>(p)=v;}
template<typename T>
inline void set_pey(Line<T> &p, T v) { std::get<3>(p)=v;}

// line, segment, rect
template<typename T>
inline T px1(const Rect<T> &p) { return std::get<0>(p);}
template<typename T>
inline T py1(const Rect<T> &p) { return std::get<1>(p);}
template<typename T>
inline T px2(const Rect<T> &p) { return std::get<2>(p);}
template<typename T>
inline T py2(const Rect<T> &p) { return std::get<3>(p);}
template<typename T>
inline void set_px1(Rect<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_py1(Rect<T> &p, T v) { std::get<1>(p)=v;}
template<typename T>
inline void set_px2(Rect<T> &p, T v) { std::get<2>(p)=v;}
template<typename T>
inline void set_py2(Rect<T> &p, T v) { std::get<3>(p)=v;}

// circle
template<typename T>
inline T pcx(const Circle<T> &p) { return std::get<0>(p);}
template<typename T>
inline T pcy(const Circle<T> &p) { return std::get<1>(p);}
template<typename T>
inline T radius(const Circle<T> &p) { return std::get<2>(p);}
template<typename T>
inline void set_pcx(Circle<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_pcy(Circle<T> &p, T v) { std::get<1>(p)=v;}
template<typename T>
inline void set_radius(Circle<T> &p, T v) { std::get<2>(p)=v;}


// arc
template<typename T>
inline T psx(const Arc<T> &p) { return std::get<0>(p);}
template<typename T>
inline T psy(const Arc<T> &p) { return std::get<1>(p);}
template<typename T>
inline T pex(const Arc<T> &p) { return std::get<2>(p);}
template<typename T>
inline T pey(const Arc<T> &p) { return std::get<3>(p);}
template<typename T>
inline T pcx(const Arc<T> &p) { return std::get<4>(p);}
template<typename T>
inline T pcy(const Arc<T> &p) { return std::get<5>(p);}
template<typename T>
inline bool cw(const Arc<T> &p) { return std::get<6>(p);}
template<typename T>
inline void set_psx(Arc<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_psy(Arc<T> &p, T v) { std::get<1>(p)=v;}
template<typename T>
inline void set_pex(Arc<T> &p, T v) { std::get<2>(p)=v;}
template<typename T>
inline void set_pey(Arc<T> &p, T v) { std::get<3>(p)=v;}
template<typename T>
inline void set_pcx(Arc<T> &p, T v) { std::get<4>(p)=v;}
template<typename T>
inline void set_pcy(Arc<T> &p, T v) { std::get<5>(p)=v;}
template<typename T>
inline void set_cw(Arc<T> &p, bool v) { std::get<6>(p)=v;}

// vertex
template<typename T>
inline T px(const Vertex<T> &p) { return std::get<0>(p);}
template<typename T>
inline T py(const Vertex<T> &p) { return std::get<1>(p);}
template<typename T>
inline jereal angle(const Vertex<T> &p) { return std::get<2>(p);}
template<typename T>
inline void set_px(Vertex<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_py(Vertex<T> &p, T v) { std::get<1>(p)=v;}
template<typename T>
inline void set_angle(Vertex<T> &p, jereal v) { std::get<2>(p)=v;}

// edge
template<typename T>
inline T psx(const Edge<T> &p) { return std::get<0>(p);}
template<typename T>
inline T psy(const Edge<T> &p) { return std::get<1>(p);}
template<typename T>
inline T pex(const Edge<T> &p) { return std::get<2>(p);}
template<typename T>
inline T pey(const Edge<T> &p) { return std::get<3>(p);}
template<typename T>
inline jereal angle(const Edge<T> &p) { return std::get<4>(p);}
template<typename T>
inline void set_psx(Edge<T> &p, T v) { std::get<0>(p)=v;}
template<typename T>
inline void set_psy(Edge<T> &p, T v) { std::get<1>(p)=v;}
template<typename T>
inline void set_pex(Edge<T> &p, T v) { std::get<2>(p)=v;}
template<typename T>
inline void set_pey(Edge<T> &p, T v) { std::get<3>(p)=v;}
template<typename T>
inline void set_angle(Edge<T> &p, jereal v) { std::get<4>(p)=v;}

template<typename T>
std::ostream& operator<<(std::ostream& os, const Point<T> &p) {
    os << "point(x:" << px(p) << ", y:" << py(p) << ")";
    return os;
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const Line<T> &p) {
    os << "line/rect(x1:" << psx(p) << ", y1:" << psy(p) << ", x2:" << pex(p) << ", y2:" << pey(p) << ")";
    return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const Vertex<T> &p) {
    os << "vertex(x:" << px(p) << ", y:" << py(p) << ", angle:" << angle(p) << ")";
    return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const Edge<T> &p) {
    os << "edge(xs:" << psx(p) << ", ys:" << psy(p) << ", xe:" << pex(p) << ", ye:" << pey(p) << ", angle:" << angle(p) << ")";
    return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const Circle<T> &p) {
    os << "circle(cx:" << pcx(p) << ", cy:" << pcy(p) << ", radius:" << radius(p) << ")";
    return os;
}

template<typename T>
std::ostream& operator<<(std::ostream& os, const Arc<T> &p) {
    os << "arc(xs:" << psx(p) << ", ys:" << psy(p) << ", xe:" << pex(p) << ", ye:" << pey(p) << ", xc:" << pcx(p) << ", yc:" << pcy(p) << ", cw:" << cw(p) << ")";
    return os;
}



} // namespace jegeo

#endif // JEGEO_MODEL_H
